﻿using System;
using System.Runtime.Serialization;
using System.Windows;
using Game.Common;
using Game.Common.Visitor;
using Game.ExtensibleObjects;

namespace Game.Map.Internal
{
    [DataContract(Namespace="game")]
    public class MapField : IMapField, IVisitorElement
    {
        public event EventHandler Changed;

        [DataMember]
        public readonly GamePoint _Point;
        
        RuntimeExtensionCollection _Extensions;
        [DataMember] 
        public SerializableExtensions _SerializableExtensions;

        bool _IsDirty;
        
        public MapField()
        {
            SetupExtensions();
        }

        [OnDeserialized]
        public void OnDeserialized2(StreamingContext c)
        {
            SetupExtensions();
        }

        public MapField(
            double coordinateX, 
            double coordinateY)
        {
            _Point =  new GamePoint(coordinateX, coordinateY);
            _SerializableExtensions = new SerializableExtensions();
            SetupExtensions();
        }

        bool IsSerializable(object obj)
        {
            bool result = false;

            var attributes = obj.GetType().GetCustomAttributes(false);
            foreach (var a in attributes)
            {
                if (a is DataContractAttribute)
                {
                    result = true;
                }
            }

            return result;
        }

        void SetupExtensions()
        {
            _Extensions = new RuntimeExtensionCollection();
            foreach (var ext in _SerializableExtensions)
            {
                if (ext is IAttachable)
                {
                    var a = ext as IAttachable;
                    a.Attach(this);
                }
                _Extensions.Add(ext);
            }

            _Extensions.CollectionChanged += (source, args) =>
            {
                foreach (IRuntimeExtension obj in args.NewItems)
                {
                    if (IsSerializable(obj))
                    {
                        _SerializableExtensions.Add(obj);
                    }
                }
            };

            foreach (var f in MapConfig.FieldExtensions)
            {
                _Extensions.Add(f.CreateExtension(this));
            }
        }

        public RuntimeExtensionCollection Extensions 
        {
            get { return _Extensions; } 
        }

        public Point Point
        {
            get { return new Point(_Point.X, _Point.Y); }
        }
        
        public bool IsDirty
        {
            get { return _IsDirty; }
            set 
            { 
                _IsDirty = value;
                FireChanged();
            }
        }

        public void Accept(IVisitor visitor)
        {
            foreach (var item in _Extensions)
            {
                var element = item as IVisitorElement;
                if (element != null)
                {
                    element.Accept(visitor);
                }
            }
        }

        void FireChanged()
        {
            _IsDirty=true;
            if (Changed != null)
            {
                Changed(this, new EventArgs());
            }
        }
        
        public override string ToString()
        {
            return "[" + _Point.ToString() + "]";
        }

    }

}
